/* tessellation.c is part of VIP program
 * Written by J. Salvador Arias, 2010
 *      CONICET, INSUE, Instituto Miguel Lillo,
 *      Miguel Lillo 205, S.M. de Tucuman (4000)
 *      Tucuman, Argentina
 *      e-mail: jsalarias@csnat.unt.edu.ar
 *
 * VIP is a free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation and
 * Creative Commons.
 *
 * This file and the VIP program is distributed in the hope
 * that it will be useful, but WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * To view a copy of this license, visit
 * http://creativecommons.org/licenses/GPL/2.0/
 * or send a letter to
 * Creative Commons, 171 Second Street, Suite 300,
 * San Francisco, California, 94105, USA.
 */

#include "tessellation.h"
#include <math.h>

static GList* StartTriangleList (SINTEGER maxCols);
static GList* RemoveInvalid (GList* triangleList);
static SFLAG IsValid (DELAUNAYTRIANGLE* tri);
static void RemoveNeighbor (DELAUNAYTRIANGLE* toDel, DELAUNAYTRIANGLE* dest);

static void InsertPoint (GList* triangleList, SCOUNTER x, SCOUNTER y, SFLAG state);

static DELAUNAYTRIANGLE* CreateTriangle (SINTEGER colA, SINTEGER rowA,
                                         SINTEGER colB, SINTEGER rowB, SINTEGER colC, SINTEGER rowC,
                                         SFLAG stateA, SFLAG stateB, SFLAG stateC);
static void ReDoTriangle (DELAUNAYTRIANGLE* reDo, SINTEGER colA, SINTEGER rowA,
                                         SINTEGER colB, SINTEGER rowB, SINTEGER colC, SINTEGER rowC,
                                         SFLAG stateA, SFLAG stateB, SFLAG stateC);
static void CalculateCircle (SINTEGER colA, SINTEGER rowA, SINTEGER colB, SINTEGER rowB, SINTEGER colC, SINTEGER rowC,
                      SREAL* cX, SREAL* cY, SREAL* r);

static SFLAG IsCellInside (SINTEGER pCol, SINTEGER pRow, DELAUNAYTRIANGLE* probe);

static void SetNeighbor (DELAUNAYTRIANGLE* triA, DELAUNAYTRIANGLE* triB);
static void ReplaceNeighbors (DELAUNAYTRIANGLE* dest, DELAUNAYTRIANGLE* src);
static void SearchCommonSegment (DELAUNAYTRIANGLE* triA, DELAUNAYTRIANGLE* triB, SCOUNTER* segmentA, SCOUNTER* segmentB);

static void IsLegal (DELAUNAYTRIANGLE* src, DELAUNAYTRIANGLE* tri);
static SREAL CalcDist (SREAL x1, SREAL x2, SREAL y1, SREAL y2);

static SCOUNTER idCount = 0;

GList* MakeVoronoi (BITFIELD* iniA, BITFIELD* iniB) {
 INTARRAY* cellList;
 GList* triangles;
 SFLAG state;
 SCOUNTER i, actCell;
 SINTEGER row, col;
 SREAL sX;
 SINTEGER maxCols;

 idCount = 0;
 cellList = CreateIntArray (GETNUMCELLS);
 for (i = 0; i < GETNUMCELLS; ++ i) {
   if (IsBitOn (iniA, i) == TRUE)
     AddToArray (cellList, i);
   else if (IsBitOn (iniB, i) == TRUE)
     AddToArray (cellList, i);
 }
 /* Randomize the list */
 ShuffleIntArray (cellList);
 /* Add points to the triangulation */
 maxCols = 360.00 / GETGRIDSIZE;
 triangles = StartTriangleList (maxCols);
 for (i = 0; i < GetArraySize (cellList); ++ i) {
   actCell = GetFromArray (cellList, i);
   state = STATE_NOCELL;
   if (IsBitOn (iniA, actCell) == TRUE)
     state = STATE_SETA;
   else if (IsBitOn (iniB, actCell) == TRUE)
     state = STATE_SETB;
   if (state != STATE_NOCELL) {
     GetColRowFromCell (actCell, &row, &col);
     InsertPoint (triangles, col, row, state);
     sX = (col * GETGRIDSIZE) + GETGRIDSTARTX;
     if (sX <= maxCols / 4)
       InsertPoint (triangles, col + maxCols, row, state);
     else if (sX >= (3 * maxCols / 4))
       InsertPoint (triangles, col - maxCols, row, state);
   }
 }
 /* Destroy the list */
 DestroyIntArray (cellList);
 triangles = RemoveInvalid (triangles);
 return triangles;
}

void DestroyTriangleList (GList* triangleList) {
 DestroyList (triangleList, sizeof (DELAUNAYTRIANGLE));
}

GList* RemoveInvalid (GList* triangleList) {
 GList* head;
 GList* nav;
 DELAUNAYTRIANGLE* actTri;

 head = NULL;
 for (nav = triangleList; nav != NULL;) {
   actTri = (DELAUNAYTRIANGLE*) nav -> data;
   if (IsValid (actTri)) {
     if (head == NULL)
       head = nav;
     nav = g_list_next (nav);
     continue;
   }
   nav = g_list_next (nav);
   RemoveNeighbor (actTri, actTri -> neighbor [0]);
   RemoveNeighbor (actTri, actTri -> neighbor [1]);
   RemoveNeighbor (actTri, actTri -> neighbor [2]);
   DestroyLinkElement (actTri -> list, sizeof (DELAUNAYTRIANGLE));
 }
 return head;
}

SFLAG IsValid (DELAUNAYTRIANGLE* tri) {
 SCOUNTER i;
 SCOUNTER minNo, maxNo, stA, stB;

 minNo = maxNo = stA = stB = 0;
 for (i = 0; i < 3; ++ i) {
   if ((tri -> col [i] < 0) || (tri -> row [i] < 0))
     ++ minNo;
   if ((tri -> col [i] >= GETNUMCOLS) || (tri -> row [i] >= GETNUMROWS))
     ++ maxNo;
   if (tri -> state [i] == STATE_SETA)
     ++ stA;
   else if (tri -> state [i] == STATE_SETB)
     ++ stB;
 }
 if ((minNo == 3) || (maxNo == 3)) return FALSE;
 if ((stA == 0) || (stB == 0)) return FALSE;
 return TRUE;
}

void RemoveNeighbor (DELAUNAYTRIANGLE* toDel, DELAUNAYTRIANGLE* dest) {
 SCOUNTER n;

 if ((toDel == NULL) || (dest == NULL)) return;
 for (n = 0; n < 3;  ++ n) {
   if (dest -> neighbor [n] != toDel) continue;
   dest -> neighbor [n] = NULL;
   break;
 }
}

void InsertPoint (GList* triangleList, SCOUNTER x, SCOUNTER y, SFLAG state) {
 GList* nav;
 GList* nuList;
 DELAUNAYTRIANGLE* destA;
 DELAUNAYTRIANGLE* destB;
 DELAUNAYTRIANGLE* probe;
 DELAUNAYTRIANGLE* nuTriA;
 DELAUNAYTRIANGLE* nuTriB;
 DELAUNAYTRIANGLE* nuTriC;
 DELAUNAYTRIANGLE* nuTriD;
 SCOUNTER i;
 SCOUNTER segmentA, segmentB;

 destA = destB = NULL;
 segmentA = segmentB = 0;
 /* Look for the initial triangle */
 for (nav = triangleList; nav != NULL; nav = g_list_next (nav)) {
   probe = (DELAUNAYTRIANGLE*) nav -> data;
   if (IsCellInside (x, y, probe)) {
     destA = probe;
     break;
   }
 }
 /* check in neighbors (for the case of incidence in and edge */
 for (i = 0; i < 3; ++ i) {
   if (destA -> neighbor [i] == NULL) continue;
   if (IsCellInside (x, y, destA -> neighbor [i])) {
     destB = destA -> neighbor [i];
     break;
   }
 }
 if (destB != NULL) {
   SearchCommonSegment (destA, destB, &segmentA, &segmentB);
   if (segmentA == 0) {
     nuTriA = CreateTriangle (x,y,  destA -> col [0], destA -> row [0],  destA -> col [1], destA -> row [1],
                              state, destA -> state [0], destA -> state [1]);
     nuTriB = CreateTriangle (x,y,  destA -> col [0], destA -> row [0],  destA -> col [2], destA -> row [2],
                              state, destA -> state [0], destA -> state [2]);
   }
   else if (segmentA == 1) {
     nuTriA = CreateTriangle (x,y,  destA -> col [1], destA -> row [1],  destA -> col [2], destA -> row [2],
                              state, destA -> state [1], destA -> state [2]);
     nuTriB = CreateTriangle (x,y,  destA -> col [1], destA -> row [1],  destA -> col [0], destA -> row [0],
                              state, destA -> state [1], destA -> state [0]);
   }
   else {
     nuTriA = CreateTriangle (x,y,  destA -> col [2], destA -> row [2],  destA -> col [1], destA -> row [1],
                              state, destA -> state [2], destA -> state [1]);
     nuTriB = CreateTriangle (x,y,  destA -> col [2], destA -> row [2],  destA -> col [0], destA -> row [0],
                              state, destA -> state [2], destA -> state [0]);
   }
   if (segmentB == 0) {
     nuTriC = CreateTriangle (x,y,  destB -> col [0], destB -> row [0],  destB -> col [1], destB -> row [1],
                              state, destB -> state [0], destB -> state [1]);
     nuTriD = CreateTriangle (x,y,  destB -> col [0], destB -> row [0],  destB -> col [2], destB -> row [2],
                              state, destB -> state [0], destB -> state [2]);
   }
   else if (segmentB == 1) {
     nuTriC = CreateTriangle (x,y,  destB -> col [1], destB -> row [1],  destB -> col [2], destB -> row [2],
                              state, destB -> state [1], destB -> state [2]);
     nuTriD = CreateTriangle (x,y,  destB -> col [1], destB -> row [1],  destB -> col [0], destB -> row [0],
                              state, destB -> state [1], destB -> state [0]);
   }
   else {
     nuTriC = CreateTriangle (x,y,  destB -> col [2], destB -> row [2],  destB -> col [1], destB -> row [1],
                              state, destB -> state [2], destB -> state [1]);
     nuTriD = CreateTriangle (x,y,  destB -> col [2], destB -> row [2],  destB -> col [0], destB -> row [0],
                              state, destB -> state [2], destB -> state [0]);
   }
   SetNeighbor (nuTriA, nuTriB);
   SetNeighbor (nuTriA, nuTriC);
   SetNeighbor (nuTriA, nuTriD);
   SetNeighbor (nuTriB, nuTriC);
   SetNeighbor (nuTriB, nuTriD);
   SetNeighbor (nuTriC, nuTriD);
   ReplaceNeighbors (nuTriA, destA);
   ReplaceNeighbors (nuTriB, destA);
   ReplaceNeighbors (nuTriC, destB);
   ReplaceNeighbors (nuTriD, destB);
   nuTriA -> list = destA -> list;
   nuTriA -> list -> data = nuTriA;
   nuTriC -> list = destB -> list;
   nuTriC -> list -> data = nuTriC;
   nuList = g_list_append (NULL, nuTriB);
   nuTriB -> list = nuList;
   nuList = g_list_append (NULL, nuTriD);
   nuTriD -> list = nuList;
   PutAtListEnd (nuTriC -> list, nuTriB -> list);
   PutAtListEnd (nuTriB -> list, nuTriD -> list);
   g_slice_free1 (sizeof (DELAUNAYTRIANGLE), destA);
   g_slice_free1 (sizeof (DELAUNAYTRIANGLE), destB);
   IsLegal (NULL, nuTriA);
   IsLegal (NULL, nuTriB);
   IsLegal (NULL, nuTriC);
   IsLegal (NULL, nuTriD);
 }
 else if (destA != NULL) {
   nuTriA = CreateTriangle (x,y,  destA -> col [0], destA -> row [0],  destA -> col [1], destA -> row [1],
                              state, destA -> state [0], destA -> state [1]);
   nuTriB = CreateTriangle (x,y,  destA -> col [1], destA -> row [1],  destA -> col [2], destA -> row [2],
                              state, destA -> state [1], destA -> state [2]);
   nuTriC = CreateTriangle (x,y,  destA -> col [0], destA -> row [0],  destA -> col [2], destA -> row [2],
                              state, destA -> state [0], destA -> state [2]);
   SetNeighbor (nuTriA, nuTriB);
   SetNeighbor (nuTriA, nuTriC);
   SetNeighbor (nuTriB, nuTriC);
   ReplaceNeighbors (nuTriA, destA);
   ReplaceNeighbors (nuTriB, destA);
   ReplaceNeighbors (nuTriC, destA);
   nuTriA -> list = destA -> list;
   nuTriA -> list -> data = nuTriA;
   nuList = g_list_append (NULL, nuTriB);
   nuTriB -> list = nuList;
   nuList = g_list_append (NULL, nuTriC);
   nuTriC -> list = nuList;
   PutAtListEnd (nuTriA -> list, nuTriB -> list);
   PutAtListEnd (nuTriB -> list, nuTriC -> list);
   g_slice_free1 (sizeof (DELAUNAYTRIANGLE), destA);
   IsLegal (NULL, nuTriA);
   IsLegal (NULL, nuTriB);
   IsLegal (NULL, nuTriC);
 }
}

void ReplaceNeighbors (DELAUNAYTRIANGLE* dest, DELAUNAYTRIANGLE* src) {
 SCOUNTER a, b, b1, b2, segmentB;

 if ((dest == NULL) || (src == NULL)) return;
 b1 = b2 = -1;
 for (a = 0; a < 3; ++ a) {
   for (b = 0; b < 3; ++ b) {
     if ((dest -> col [a] == src -> col [b]) && (dest -> row [a] == src -> row [b])) {
       if (b1 == -1) {
         b1 = b;
       }
       else if (b2 == -1) {
         b2 = b;
       }
       break;
     }
   }
 }
 if (b2 == -1) return;
 if ((b1 != 0) && (b2 != 0))
   segmentB = 0;
 else if ((b1 != 1) && (b2 != 1))
   segmentB = 1;
 else
   segmentB = 2;
 SetNeighbor (dest, src -> neighbor [segmentB]);
}

void SetNeighbor (DELAUNAYTRIANGLE* triA, DELAUNAYTRIANGLE* triB) {
 SCOUNTER a, b, a1, a2, b1, b2, segmentA, segmentB;

 if ((triA == NULL) || (triB == NULL)) return;
 a1 = a2 = b1 = b2 = -1;
 for (a = 0; a < 3; ++ a) {
   for (b = 0; b < 3; ++ b) {
     if ((triA -> col [a] == triB -> col [b]) && (triA -> row [a] == triB -> row [b])) {
       if (a1 == -1) {
         a1 = a;
         b1 = b;
       }
       else if (a2 == -1) {
         a2 = a;
         b2 = b;
       }
       break;
     }
   }
 }
 if (a2 == -1) return;
 if ((a1 != 0) && (a2 != 0))
   segmentA = 0;
 else if ((a1 != 1) && (a2 != 1))
   segmentA = 1;
 else
   segmentA = 2;
 if ((b1 != 0) && (b2 != 0))
   segmentB = 0;
 else if ((b1 != 1) && (b2 != 1))
   segmentB = 1;
 else
   segmentB = 2;
 triA -> neighbor [segmentA] = triB;
 triB -> neighbor [segmentB] = triA;
}

void SearchCommonSegment (DELAUNAYTRIANGLE* triA, DELAUNAYTRIANGLE* triB, SCOUNTER* segmentA, SCOUNTER* segmentB) {
 SCOUNTER a, b;

 for (a = 0; a < 3; ++ a) {
   if (triA -> neighbor [a] != triB) continue;
   for (b = 0; b < 3; ++ b) {
     if (triB -> neighbor [b] != triA) continue;
     if (segmentA != NULL)
       *segmentA = a;
     *segmentB = b;
     break;
   }
   break;
 }
}

void IsLegal (DELAUNAYTRIANGLE* src, DELAUNAYTRIANGLE* tri) {
 DELAUNAYTRIANGLE* nei;
 DELAUNAYTRIANGLE* tmpA [3];
 DELAUNAYTRIANGLE* tmpN [3];
 SCOUNTER a, n, segmentN, tRow, tCol;
 SREAL dist;
 SFLAG isLegal;
 SFLAG tState;

 segmentN = 0;
 for (;;) {
   isLegal = TRUE;
   for (n = 0; n < 3;  ++ n) {
     if (tri -> neighbor [n] == NULL) continue;
     if (tri -> neighbor [n] == src) continue;
     nei = tri -> neighbor [n];
     SearchCommonSegment (tri, nei, NULL, &segmentN);
     dist = CalcDist (tri -> cX, nei -> col [segmentN], tri -> cY, nei -> row [segmentN]) + 0.000005;
     if (dist < tri -> r) {
       /* Illegal triangle */
       isLegal = FALSE;
       for (a = 0; a < 3; ++ a) {   /* Save the neghbors of both triangles */
         tmpN [a] = nei -> neighbor [a];
         tmpA [a] = tri -> neighbor [a];
       }
       /* ReDo the triangles */
       if (n == 0) {
         tCol = tri -> col [1];
         tRow = tri -> row [1];
         tState = tri -> state [1];
         ReDoTriangle (tri, tri -> col [0], tri -> row [0], nei -> col [segmentN], nei -> row [segmentN],
                            tri -> col [2], tri -> row [2], tri -> state [0], nei -> state [segmentN], tri -> state [2]);
         ReDoTriangle (nei, tri -> col [0], tri -> row [0], nei -> col [segmentN], nei -> row [segmentN], tCol, tRow,
                            tri -> state [0], nei -> state [segmentN], tState);
       }
       else if (n == 1) {
         tCol = tri -> col [0];
         tRow = tri -> row [0];
         tState = tri -> state [0];
         ReDoTriangle (tri, tri -> col [1], tri -> row [1], nei -> col [segmentN], nei -> row [segmentN],
                            tri -> col [2], tri -> row [2], tri -> state [1], nei -> state [segmentN], tri -> state [2]);
         ReDoTriangle (nei, tri -> col [1], tri -> row [1], nei -> col [segmentN], nei -> row [segmentN], tCol, tRow,
                            tri -> state [1], nei -> state [segmentN], tState);
       }
       else if (n == 2) {
         tCol = tri -> col [0];
         tRow = tri -> row [0];
         tState = tri -> state [0];
         ReDoTriangle (tri, tri -> col [1], tri -> row [1], nei -> col [segmentN], nei -> row [segmentN],
                            tri -> col [2], tri -> row [2], tri -> state [1], nei -> state [segmentN], tri -> state [2]);
         ReDoTriangle (nei, tri -> col [2], tri -> row [2], nei -> col [segmentN], nei -> row [segmentN], tCol, tRow,
                            tri -> state [2], nei -> state [segmentN], tState);
       }
       for (a = 0; a < 3; ++ a) {   /* Set the neoghbors */
         if (tmpN [a] != tri)
           SetNeighbor (tri, tmpN [a]);
         SetNeighbor (tri, tmpA [a]);
         SetNeighbor (nei, tmpN [a]);
         if (tmpA [a] != nei)
           SetNeighbor (nei, tmpA [a]);
       }
       IsLegal (tri, nei);
       break;
     }
   }
   if (isLegal == TRUE) break;
 }
}

GList* StartTriangleList (SINTEGER maxCols) {
 GList* list;
 DELAUNAYTRIANGLE* nuTri;
 SINTEGER sX, sY, startX, startY;

 startX = GETGRIDSTARTX / GETGRIDSIZE;
 startY = GETGRIDSTARTY / GETGRIDSIZE;
 sX = (GETNUMCOLS / 2) + startX;
 sY = (GETNUMROWS / 2) + startY;
 nuTri = CreateTriangle (sX, (-maxCols * 20) + sY,  (-maxCols * 17) + sX, (maxCols * 10) + sY,
                         (maxCols * 17) + sX, (maxCols * 10) + sY,
                         STATE_NOCELL, STATE_NOCELL, STATE_NOCELL);
 list = g_list_append (NULL, nuTri);
 nuTri -> list = list;
 return list;
}

DELAUNAYTRIANGLE* CreateTriangle (SINTEGER colA, SINTEGER rowA,
                                         SINTEGER colB, SINTEGER rowB, SINTEGER colC, SINTEGER rowC,
                                         SFLAG stateA, SFLAG stateB, SFLAG stateC) {
 DELAUNAYTRIANGLE* nuTri;
 SCOUNTER i;

 nuTri = g_slice_alloc (sizeof (DELAUNAYTRIANGLE));
 nuTri -> col [0] = colA;
 nuTri -> row [0] = rowA;
 nuTri -> state [0] = stateA;
 nuTri -> col [1] = colB;
 nuTri -> row [1] = rowB;
 nuTri -> state [1] = stateB;
 nuTri -> col [2] = colC;
 nuTri -> row [2] = rowC;
 nuTri -> state [2] = stateC;
 nuTri -> id = idCount;
 ++ idCount;
 for (i = 0; i < 3; ++ i)
   nuTri -> neighbor [i] = NULL;
 CalculateCircle (colA, rowA, colB, rowB, colC, rowC, &nuTri -> cX, &nuTri -> cY, &nuTri -> r);
 nuTri -> list = NULL;
 return nuTri;
}

void ReDoTriangle (DELAUNAYTRIANGLE* reDo, SINTEGER colA, SINTEGER rowA,
                                         SINTEGER colB, SINTEGER rowB, SINTEGER colC, SINTEGER rowC,
                                         SFLAG stateA, SFLAG stateB, SFLAG stateC) {
 SCOUNTER i;

 reDo -> col [0] = colA;
 reDo -> row [0] = rowA;
 reDo -> state [0] = stateA;
 reDo -> col [1] = colB;
 reDo -> row [1] = rowB;
 reDo -> state [1] = stateB;
 reDo -> col [2] = colC;
 reDo -> row [2] = rowC;
 reDo -> state [2] = stateC;
 for (i = 0; i < 3; ++ i)
   reDo -> neighbor [i] = NULL;
 CalculateCircle (colA, rowA, colB, rowB, colC, rowC, &reDo -> cX, &reDo -> cY, &reDo -> r);
}


void CalculateCircle (SINTEGER colA, SINTEGER rowA, SINTEGER colB, SINTEGER rowB, SINTEGER colC, SINTEGER rowC,
                      SREAL* cX, SREAL* cY, SREAL* r) {
 SREAL aX, aY, bX, bY, aN, bN, deno;

 aY = rowA - rowC;
 aX = colA - colC;
 bY = rowB - rowC;
 bX = colB - colC;
 deno = 2 * ((aX * bY) - (aY * bX));
 if ((deno>=-0.0000001) && (deno <= 0.0000001)) {
   /* Colineal or unsorted points */
  *cX = *cY = *r = -1;
   return;
 }
 aN = (aX * aX) + (aY * aY);
 bN = (bX * bX) + (bY * bY);
 *cX = ((aN * bY) - (bN * aY)) / deno;
 *cY = ((bN * aX) - (aN * bX)) / deno;
 *r = CalcDist (*cX, aX, *cY, aY);
 *cX += colC;
 *cY += rowC;
}

SFLAG IsCellInside (SINTEGER pCol, SINTEGER pRow, DELAUNAYTRIANGLE* probe) {
 SREAL v0v0, v0v1, v0v2, v1v1, v1v2;
 SREAL deno;
 SREAL u, v;

 v0v0 = ((probe -> row [2] - probe -> row [0]) * (probe -> row [2] - probe -> row [0])) +
        ((probe -> col [2] - probe -> col [0]) * (probe -> col [2] - probe -> col [0]));
 v0v1 = ((probe -> row [2] - probe -> row [0]) * (probe -> row [1] - probe -> row [0])) +
        ((probe -> col [2] - probe -> col [0]) * (probe -> col [1] - probe -> col [0]));
 v0v2 = ((probe -> row [2] - probe -> row [0]) * (pRow - probe -> row [0])) +
        ((probe -> col [2] - probe -> col [0]) * (pCol - probe -> col [0]));
 v1v1 = ((probe -> row [1] - probe -> row [0]) * (probe -> row [1] - probe -> row [0])) +
        ((probe -> col [1] - probe -> col [0]) * (probe -> col [1] - probe -> col [0]));
 v1v2 = ((probe -> row [1] - probe -> row [0]) * (pRow - probe -> row [0])) +
        ((probe -> col [1] - probe -> col [0]) * (pCol - probe -> col [0]));
 deno = (v0v0 * v1v1) - (v0v1 * v0v1);
 u = ((v1v1 * v0v2) - (v0v1 * v1v2)) / deno;
 v = ((v0v0 * v1v2) - (v0v1 * v0v2)) / deno;
 if ((u < 0) || (v < 0) || ((u + v) > 1.0000001)) return FALSE;
 return TRUE;
}

#include <stdio.h>
SREAL CalcDist (SREAL x1, SREAL x2, SREAL y1, SREAL y2) {
 SREAL toRet;
 toRet = sqrt (((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));
 printf ("%f ", toRet);
 return toRet;
}
